package web

import (
	"html/template"
	"log"
	"net/http"
	"path"
	"strings"
)

// HandlerFunc 定义simple框架使用的请求处理函数类型
// 参数: *Context - 请求上下文
// 返回: 无返回值
type HandlerFunc func(*Context)

// RouterGroup 路由组，用于分组管理路由
// prefix: 路由组前缀
// middlewares: 中间件函数列表
// parent: 父路由组，支持嵌套
// engine: 引擎实例，所有路由组共享同一个引擎
type RouterGroup struct {
	prefix      string
	middlewares []HandlerFunc // support middleware
	parent      *RouterGroup  // support nesting
	engine      *Engine       // all groups share a Engine instance
}

// Engine 引擎，是simple框架的核心
// RouterGroup: 嵌入的路由组
// router: 路由器实例
// groups: 所有路由组列表
// htmlTemplates: HTML模板实例
// funcMap: HTML模板函数映射
type Engine struct {
	*RouterGroup
	router        *router
	groups        []*RouterGroup     // store all groups
	htmlTemplates *template.Template // for html render
	funcMap       template.FuncMap   // for html render
}

// SetFuncMap 设置HTML模板的函数映射
// funcMap: 模板函数映射表
func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
	engine.funcMap = funcMap
}

// LoadHTMLGlob 加载HTML模板文件
// pattern: 模板文件路径匹配模式，例如 "./templates/*"
func (engine *Engine) LoadHTMLGlob(pattern string) {
	engine.htmlTemplates = template.Must(template.New("").Funcs(engine.funcMap).ParseGlob(pattern))
}

// New 创建一个新的Engine实例
// 返回: 新创建的Engine实例
func New() *Engine {
	engine := &Engine{router: newRouter()}
	engine.RouterGroup = &RouterGroup{engine: engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
}

// Default 创建一个默认配置的Engine实例
// 返回: 配置了Logger和Recovery中间件的Engine实例
func Default() *Engine {
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

// Group 创建一个新的路由组
// prefix: 路由组的前缀
// 返回: 新创建的路由组
func (group *RouterGroup) Group(prefix string) *RouterGroup {
	engine := group.engine
	newGroup := &RouterGroup{
		prefix: group.prefix + prefix,
		parent: group,
		engine: engine,
	}
	engine.groups = append(engine.groups, newGroup)
	return newGroup
}

// addRoute 添加路由规则
// method: HTTP方法，如GET、POST
// comp: 路由路径
// handler: 请求处理函数
func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) {
	pattern := group.prefix + comp
	log.Printf("Route %4s - %s", method, pattern)
	group.engine.router.addRoute(method, pattern, handler)
}

// GET 添加GET请求的路由规则
// pattern: 路由路径模式
// handler: 请求处理函数
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
	group.addRoute("GET", pattern, handler)
}

// POST 添加POST请求的路由规则
// pattern: 路由路径模式
// handler: 请求处理函数
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
	group.addRoute("POST", pattern, handler)
}

// Run 启动HTTP服务器
// addr: 服务器监听地址，例如 ":8080"
// 返回: 启动服务器过程中可能出现的错误
func (engine *Engine) Run(addr string) (err error) {
	return http.ListenAndServe(addr, engine)
}
// Use 为路由组添加中间件
// middlewares: 一个或多个中间件函数
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
	group.middlewares = append(group.middlewares, middlewares...)
}

// ServeHTTP 实现http.Handler接口，处理HTTP请求
// w: HTTP响应写入器
// req: HTTP请求对象
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var middlewares []HandlerFunc
	for _, group := range engine.groups {
		if strings.HasPrefix(req.URL.Path, group.prefix) {
			middlewares = append(middlewares, group.middlewares...)
		}
	}
	c := newContext(w, req)
	c.handlers = middlewares
	c.engine = engine
	engine.router.handle(c)
}

// create static handler
func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
	absolutePath := path.Join(group.prefix, relativePath)
	fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
	return func(c *Context) {
		file := c.Param("filepath")
		// Check if file exists and/or if we have permission to access it
		if _, err := fs.Open(file); err != nil {
			c.Status(http.StatusNotFound)
			return
		}

		fileServer.ServeHTTP(c.Writer, c.Req)
	}
}

// serve static files
func (group *RouterGroup) Static(relativePath string, root string) {
	handler := group.createStaticHandler(relativePath, http.Dir(root))
	urlPattern := path.Join(relativePath, "/*filepath")
	// Register GET handlers
	group.GET(urlPattern, handler)
}
